package com.easy.module.system.service.impl;

import com.easy.framework.common.utils.ArithmeticUtil;
import com.easy.framework.common.utils.ConvertUtil;
import com.easy.framework.common.utils.ip.IpUtils;
import com.easy.module.system.service.ISysMonitorService;
import org.springframework.stereotype.Service;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.CentralProcessor.TickType;
import oshi.hardware.GlobalMemory;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.util.Util;

import java.util.*;

@Service
public class SysMonitorServiceImpl implements ISysMonitorService {

    private SystemInfo systemInfo = new SystemInfo();

    @Override
    public Map<String, Object> getOsInfo() {
        Properties props = System.getProperties();
        Map<String, Object> map = new HashMap<>();
        map.put("computerName", IpUtils.getHostName());
        map.put("computerIp", IpUtils.getHostIp());
        map.put("osName", props.getProperty("os.name"));
        map.put("osArch", props.getProperty("os.arch"));
        map.put("userDir", props.getProperty("user.dir"));
        return map;
    }

    @Override
    public Map<String, Object> getJvmInfo() {
        Properties props = System.getProperties();
        Map<String, Object> map = new HashMap<>();
        map.put("total", Runtime.getRuntime().totalMemory());
        map.put("max", Runtime.getRuntime().maxMemory());
        map.put("free", Runtime.getRuntime().freeMemory());
        map.put("version", props.getProperty("java.version"));
        map.put("home", props.getProperty("java.home"));
        return map;
    }

    @Override
    public Map<String, Object> getCpuInfo() {
        CentralProcessor processor = systemInfo.getHardware().getProcessor();
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(1000);
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
        Map<String, Object> map = new HashMap<>();
        map.put("cpuNum", processor.getLogicalProcessorCount());
        map.put("total", totalCpu);
        map.put("sys", cSys);
        map.put("used", user);
        map.put("wait", iowait);
        map.put("free", idle);
        return map;
    }

    @Override
    public Map<String, Object> getMemoryInfo() {
        GlobalMemory memory = systemInfo.getHardware().getMemory();
        Map<String, Object> map = new HashMap<>();
        map.put("total", memory.getTotal());
        map.put("used", memory.getTotal() - memory.getAvailable());
        map.put("free", memory.getAvailable());
        return map;
    }

    @Override
    public List<Map<String, Object>> getDiskInfo() {
        FileSystem fileSystem = systemInfo.getOperatingSystem().getFileSystem();
        List<OSFileStore> osFileStoreList = fileSystem.getFileStores();
        List<Map<String, Object>> list = new ArrayList<>();
        for (OSFileStore fs : osFileStoreList) {
            long free = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            long used = total - free;
            Map<String, Object> map = new HashMap<>();
            map.put("dirName", fs.getMount());
            map.put("sysTypeName", fs.getType());
            map.put("typeName", fs.getName());
            map.put("total", ConvertUtil.toFileSize(total));
            map.put("free", ConvertUtil.toFileSize(free));
            map.put("used", ConvertUtil.toFileSize(used));
            map.put("usage", ArithmeticUtil.mul(ArithmeticUtil.div(used, total, 4), 100));
            list.add(map);
        }
        return list;
    }
}
